export class PromisePool {
  concurrency: number;
  running: number;
  queue: any[];
  constructor(concurrency: number) {
    this.concurrency = concurrency;
    this.queue = [];
    this.running = 0;
  }

  add(task: any) {
    this.queue.push(task);
    this.run();
  }

  run() {
    while (this.running < this.concurrency && this.queue.length) {
      const task = this.queue.shift();
      this.running++;
      task().finally(() => {
        this.running--;
        this.run();
      });
    }
  }
}

export class WorkerPool {
  private pool: any[];
  private queue: { task: any; resolve: (value: any) => void }[] | any[];
  constructor(maxWorkers = navigator.hardwareConcurrency || 4) {
    this.pool = new Array(maxWorkers).fill([]).map((scriptURL) => new Worker(scriptURL));
    this.queue = [];
  }

  execute(task: any) {
    return new Promise((resolve) => {
      this.queue.push({ task, resolve });
      this.dispatch();
    });
  }

  dispatch() {
    if (this.queue.length === 0) return;
    const worker = this.pool.find((w) => !w.busy);
    if (worker) {
      worker.busy = true;
      const { task, resolve } = this.queue.shift();
      worker.postMessage(task);
      worker.onmessage = (e: { data: any; }) => {
        resolve(e.data);
        worker.busy = false;
        this.dispatch();
      };
    }
  }
}